import LinkListNode, {LinkList} from "./LinkList";
import {LinkedListRange} from "./LinkedListRange";

export class MultiDictionary<K, V> {
    private readonly _linkedList: LinkList<V>;
    private readonly _dictionary: Map<K, LinkedListRange<V>>;

    constructor() {
        this._linkedList = new LinkList<V>();
        this._dictionary = new Map<K, LinkedListRange<V>>();
    }

    get Count() {
        return this._dictionary.size;
    }

    getLinkedListRange(key: K) {
        return this._dictionary.get(key);
    }

    Clear(): void {
        this._linkedList.Clear();
        this._dictionary.clear();
    }

    Contains(key: K, value?: V): boolean {
        if (!value) {
            return this._dictionary.has(key);
        }
        return this._dictionary.get(key)?.Contains(value)
    }

    get(key: K): LinkedListRange<V> {
        return this._dictionary.get(key);
    }

    Add(key: K, value: V): void {
        if (this._dictionary.has(key)) {
            let range: LinkedListRange<V> = this._dictionary.get(key);
            this._linkedList.AddBefore(range.terminal, value);
        } else {
            let first = this._linkedList.AddLast(value);
            let terminal = this._linkedList.AddLast(undefined);
            this._dictionary.set(key, new LinkedListRange(first, terminal));
        }
    }

    Remove(key: K, value: V): boolean {
        if (this._dictionary.has(key)) {
            let range = this._dictionary.get(key);
            for (let current = range.first; current != null && current != range.terminal; current = current.Next) {
                if (this.isObjectValueEqual(current.Value,value)) {
                    if (current == range.first) {
                        let next: LinkListNode<V> = current.Next;
                        if (next == range.terminal) {
                            this._linkedList.Remove2(next);
                            this._dictionary.delete(key);
                        } else {
                            let newvalue: LinkedListRange<V> = this._dictionary.get(key);
                            newvalue = new LinkedListRange<V>(next, range.terminal);
                        }
                    }
                    this._linkedList.Remove2(current);
                    return true;
                }
            }
        }

        return false;
    }

    RemoveAll(key: K): boolean {
        if (this._dictionary.has(key)) {
            let range = this._dictionary.get(key);
            this._dictionary.delete(key);
            let current = range.first;
            while (current != null) {
                let next = current != range.terminal ? current.Next : null;
                this._linkedList.Remove2(current);
                current = next;
            }
            return true;
        }

        return false;
    }


     isObjectValueEqual(a, b){
        // Object.getOwnPropertyNames()方法返回一个由指定对象的所有自身属性的属性名（包括不可枚举属性但不包括Symbol值作为名称的属性）组成的数组
        // 换句话来说 Object.getOwnPropertyNames()方法返回的是对象所有 key 组成的数组 list
        let aProps = Object.getOwnPropertyNames(a)
        let bProps = Object.getOwnPropertyNames(b)
        if (aProps.length != bProps.length) {
            return false
        }

        for (let i = 0; i < aProps.length; i++) {
            let propName = aProps[i]
            if (typeof a[propName] === 'object') {
                let judge = this.isObjectValueEqual(a[propName], b[propName])
                if (!judge) {
                    return false
                }
            } else if (a[propName] !== b[propName]) {
                return false
            }
        }
        return true
    }

}